/*  This file is part of the comicconquer project
    Copyright (C) 2010 Reach <reach334@gmail.com>

    ComicConquer is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This software is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public 
    License along with this software.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "ZipContainer.h"

#define BUFFERSIZE (1024*1024)

ZipContainer::ZipContainer(const QString& zipFileName)
{
    In_Log(__FUNCTION__);

    m_zipFileName = zipFileName;
    m_uf = NULL;

    if (!openZipFile())
    {
        return;
    }

    generateList();

    Out_Log(__FUNCTION__);
}

ZipContainer::~ZipContainer()
{
    In_Log(__FUNCTION__);

    unzClose(m_uf);

    Out_Log(__FUNCTION__);
}

bool ZipContainer::openZipFile()
{
    In_Log(__FUNCTION__);

    m_uf = unzOpen64(m_zipFileName.toLocal8Bit().data());

    if (m_uf == NULL)
    {

        Out_Log(__FUNCTION__);
        return false;
    }


    Out_Log(__FUNCTION__);
    return true;
}

void ZipContainer::generateList()
{
    In_Log(__FUNCTION__);

    int err;
    unz_global_info64 gi;

    err = unzGetGlobalInfo64(m_uf, &gi);
    if (err != UNZ_OK)
    {

        Out_Log(__FUNCTION__);
        return;
    }

    for (qint64 i = 0; i < gi.number_entry; i++)
    {
        char filename[256];
        unz_file_info64 file_info;
        err = unzGetCurrentFileInfo64(m_uf, &file_info, filename, sizeof(filename), NULL, 0, NULL, 0);
        if (err != UNZ_OK)
        {
            break;
        }

        QString suffix = QString(filename).right(4).toLower();
        if (suffix != ".jpg" && suffix != ".png")
        {
            if (i < gi.number_entry - 1)
            {
                unzGoToNextFile(m_uf);
            }
            continue;
        }

        unz64_file_pos filePos;
        unzGetFilePos64(m_uf, &filePos);
        m_posVec.append(filePos);

        if (i < gi.number_entry - 1)
        {
            unzGoToNextFile(m_uf);
        }
    }

    Out_Log(__FUNCTION__);
}

QByteArray* ZipContainer::extractFile(int id)
{
    In_Log(__FUNCTION__);

    if (id < 0 || id >= m_posVec.count())
    {

        Out_Log(__FUNCTION__);
        return NULL;
    }

    int err;

    err = unzGoToFilePos64(m_uf, &m_posVec[id]);
    if (err != UNZ_OK)
    {

        Out_Log(__FUNCTION__);
        return NULL;
    }

    err = unzOpenCurrentFile(m_uf);
    if (err != UNZ_OK)
    {

        Out_Log(__FUNCTION__);
        return NULL;
    }

    unsigned buffer_size = BUFFERSIZE;
    char* buffer = new char[buffer_size];
    QByteArray* byteArray = new QByteArray();

    do
    {
        err = unzReadCurrentFile(m_uf, buffer, buffer_size);
        if (err < 0)
        {
            delete[] buffer;
            delete byteArray;

            Out_Log(__FUNCTION__);
            return NULL;
        }
        byteArray->append(buffer, err);
    }while (err > 0);

    delete[] buffer;
    unzCloseCurrentFile(m_uf);


    Out_Log(__FUNCTION__);
    return byteArray;
}

QImage* ZipContainer::getImage(int id)
{
    In_Log(__FUNCTION__);

    QByteArray* byteArray = extractFile(id);
    if (byteArray == NULL)
    {

        Out_Log(__FUNCTION__);
        return NULL;
    }

    QImage* image = new QImage();
    bool ret = image->loadFromData(*byteArray);
    delete byteArray;

    if (!ret)
    {
        delete image;

        Out_Log(__FUNCTION__);
        return NULL;
    }

    Out_Log(__FUNCTION__);
    return image;
}

bool ZipContainer::isEmpty()
{
    return m_posVec.isEmpty();
}

int ZipContainer::count()
{
    return m_posVec.count();
}

QString& ZipContainer::zipFileName()
{
    return m_zipFileName;
}

void ZipContainer::reOpen()
{
    unzClose(m_uf);
    m_uf = unzOpen(m_zipFileName.toLocal8Bit().data());
}
